use std::fmt::Debug;
use tokio::task::JoinSet;

use super::{
    config, log,
    middleware::{add_middleware, Middleware},
    route::{add_route, check_init, Route},
    ProtocolTrait,
};

use std::result::Result;
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Clone, Debug)]
pub struct Server<T>
where
    T: ProtocolTrait + Clone + Sync + Send + 'static,
{
    proto: Vec<T>,
    create_time: u128,
}

#[allow(dead_code)]
impl<T> Server<T>
where
    T: ProtocolTrait + Clone + Sync + Send + 'static,
{
    /// Create a new server
    /// #
    /// # Example
    /// ```
    /// use synet::default::tcp;
    /// use synet::{route, server, log};
    /// async fn main() -> Result<(), ErrorResult> {
    ///     let status = server::Server::new()
    ///         .set_protocol(tcp::Proto::new("127.0.0.1:8899"))
    ///         .set_parser(tcp::Parser::new())
    ///         .set_debug(true)
    ///         .set_open_log(true)
    ///         .set_log_file("logs/log_file.txt")
    ///         .set_log_file_max_num(30)
    ///         .set_log_level(log::LEVEL::Trace)
    ///         .add_route(route::Route::new("1001", example::demo))
    ///         .start()
    ///         .await;
    ///     match status {
    ///         Ok(_) => println!("Server started successfully"),
    ///         Err(e) => println!("Error: {:?}", e),
    ///     }
    /// }
    /// ```
    pub fn new() -> Self {
        Self {
            proto: Vec::new(),
            create_time: 0,
        }
    }

    /// set protocol for server
    /// #
    /// # Example
    /// ```
    /// server::Server::new().set_protocol(tcp::Proto::new("127.0.0.1:8899"))
    /// ```
    pub fn set_protocol(mut self, proto: T) -> Self {
        self.proto.push(proto);
        self
    }

    /// add route for server
    /// #
    /// # Example
    /// ```
    /// server::Server::new().add_route(route::Route::new("1001", example::demo))
    /// ```
    pub fn add_route(self, route: Route) -> Self {
        if let Err(e) = add_route(route.clone()) {
            panic!("add route failed: {:?} at {:?}", e, route);
        }
        self
    }

    /// add middleware for server
    /// #
    /// # Example
    /// ```
    /// server::Server::new().add_middleware(demo_middleware(params: RequestStruct) -> MiddlewareStruct)
    /// ```
    pub fn add_middleware(self, middleware: Middleware) -> Self {
        add_middleware(middleware);
        self
    }

    /// set debug mode
    /// default is false
    /// #
    /// # Example
    /// ```
    /// server::Server::new().set_debug(true)
    /// ```
    pub fn set_debug(self, debug: bool) -> Self {
        unsafe {
            config::DEBUG = debug;
        }
        self
    }

    /// set open log
    /// default is false
    /// #
    /// # Example
    /// ```
    /// server::Server::new().set_open_log(true)
    /// ```
    pub fn set_open_log(self, open_log: bool) -> Self {
        unsafe {
            config::OPEN_LOG = open_log;
        }
        self
    }

    /// set log file
    /// default is "logs/log_file.txt"
    /// #
    /// # Example
    /// ```
    /// server::Server::new().set_log_file(String::from("logs/log_file.txt"))
    /// ```
    pub fn set_log_file(self, log_file: &'static str) -> Self {
        unsafe {
            config::LOG_FILE = log_file;
        }
        self
    }

    /// set log file max num
    /// default is 30
    /// #
    /// # Example
    /// ```
    /// server::Server::new().set_log_file_max_num(30)
    /// ```
    pub fn set_log_file_max_num(self, log_file_num: u32) -> Self {
        unsafe {
            config::LOG_FILE_MAX_NUM = log_file_num;
        }
        self
    }

    pub fn set_log_level(self, log_level: log::LEVEL) -> Self {
        unsafe {
            config::LOG_LEVEL = log_level;
        }
        self
    }

    /// get config info
    /// #
    /// # Example
    /// ```
    /// server::Server::new().get_config()
    /// ```
    pub fn get_config(&self) -> config::Config {
        config::Config::new()
    }

    /// start server
    /// #
    /// # Example
    /// ```
    /// server::Server::new()
    ///     .set_protocol(tcp::Proto::new("127.0.0.1:8899"))
    ///     .set_parser(tcp::Parser::new())
    ///     .add_route(route::Route::new("1001", example::demo))
    ///     .start()
    ///     .await;
    /// ```
    pub async fn start(mut self) -> Result<(), ServerError> {
        // Initialize the log system
        log::init().await;

        // Initialize the protocol
        if self.proto.is_empty() {
            return Err(ServerError::ProtocolNotFound);
        }
        log::info("Successfully loaded protocol module");

        if check_init() == false {
            return Err(ServerError::RoutesNotFound);
        }
        log::info("Successfully loaded routes module");

        let create_time = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis();
        self.create_time = create_time;
        log::info("Service initialization successful");

        let mut set = JoinSet::new();
        for proto in self.proto.iter() {
            let proto_clone = proto.clone();
            set.spawn(async move {
                let listen_status = proto_clone.listen();
                if let Err(e) = listen_status.await {
                    log::error(format!("server listen error: {}", e));
                    return Err(ServerError::ListenError);
                } else {
                    Ok(())
                }
            });
        }
        while let Some(result) = set.join_next().await {
            match result {
                Ok(_) => {}
                Err(e) => {
                    set.abort_all();
                    set.detach_all();
                    log::error(format!("server listen error: {}", e));
                    return Err(ServerError::ServerRunTimeError);
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum ServerError {
    ProtocolNotFound,
    RoutesNotFound,
    ListenError,
    ServerRunTimeError,
}
impl std::fmt::Display for ServerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ServerError::ProtocolNotFound => write!(f, "No protocol added to the server"),
            ServerError::RoutesNotFound => write!(f, "No routes added to the server"),
            ServerError::ListenError => write!(f, "server startup listen error"),
            ServerError::ServerRunTimeError => write!(f, "Service runtime error, not service error, please check parser and service handle"),
        }
    }
}
